#include "widget.h"
#include "ui_widget.h"
#include <fcntl.h>

Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {
  ui->setupUi(this);
  this->setWindowTitle("UDP服务端");
  m_udpServer = socket(AF_INET, SOCK_DGRAM, 0);
  if (m_udpServer == -1) {
    return;
  }

  connect(&m_timer, &QTimer::timeout, this, &Widget::onReadyRead);
  m_timer.setInterval(100);
}

Widget::~Widget() { delete ui; }

void Widget::on_btnStart_clicked() {
  if (!m_start) {
    QString ip = ui->lineEditIP->text();
    uint port = ui->lineEditPort->text().toUInt();
    // 设置服务器地址和端口
    struct sockaddr_in serverAddr;
    memset(&serverAddr, 0x00, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(port); // 指定端口
    serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    inet_pton(AF_INET, ip.toStdString().c_str(), &(serverAddr.sin_addr));

    // 绑定地址和端口
    if (bind(m_udpServer, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) ==
        -1) {
      ::close(m_udpServer);
      ui->messageShoxEdit->appendPlainText("服务器启动失败！");
      return;
    }

    ui->messageShoxEdit->appendPlainText("服务器启动成功！");
    ui->btnStart->setText("停止");
    m_start = true;

    // 将套接字设置为非阻塞模式,否则会阻塞界面
    int flags = fcntl(m_udpServer, F_GETFL, 0);
    if (flags < 0) {
      perror("fcntl F_GETFL");
      ::close(m_udpServer);
      return;
    }
    if (fcntl(m_udpServer, F_SETFL, flags | O_NONBLOCK) < 0) {
      perror("fcntl F_SETFL");
      ::close(m_udpServer);
      return;
    }

    m_timer.start();

  } else {
    // 关闭与所有客户端的连接
    m_clientList.clear();
    // 关闭TCP的监听
    ::close(m_udpServer);
    ui->messageShoxEdit->appendPlainText("服务器已停止!");
    ui->btnStart->setText("启动");
    m_start = false;
  }
}


std::string addrToStr(struct sockaddr_in &addr){
    // 将 sockaddr_in 转换为整数
  const char* ipStr = inet_ntoa(addr.sin_addr);
  uint16_t port = ntohs(addr.sin_port);
  std::string portStr = std::to_string(port);
  return std::string (ipStr) + ":" + portStr;
}

void Widget::onReadyRead() {

  // 异步接收数据
  struct sockaddr_in client_addr{};
  socklen_t addr_len = sizeof(client_addr);

  // 接收数据
  char recvBuffer[1024];
  memset(recvBuffer, 0, sizeof(recvBuffer));
  ssize_t recvLen = recvfrom(m_udpServer, recvBuffer, sizeof(recvBuffer) - 1, 0, (struct sockaddr *)&client_addr, &addr_len);
  if (recvLen > 0) {
    recvBuffer[recvLen] = '\0';
  } else if (recvLen == 0) {
    //对方关闭
    return ;
  } else {
    //没有数据
    return ;
  }

  std::string key = addrToStr(client_addr);
  m_clientList[key] = client_addr;

  QString msg(recvBuffer);
  QString str = QString("收到了%1:消息:%2").arg(key.c_str()).arg(msg);
  ui->messageShoxEdit->appendPlainText(str);
}

void Widget::on_btnSend_clicked() {
  // 获取要发送的内容
  QString msg = ui->messageEdit->text();
  QByteArray data = msg.toUtf8(); // 转换为utf8字节数组
  std::string strmsg = data.toStdString();

  // 群发消息
  auto dosend = [this, strmsg](struct sockaddr_in  addr) {

  ssize_t sendLen = sendto(m_udpServer, strmsg.c_str(),
                               strmsg.size(),0, (struct sockaddr *)&addr,sizeof(addr));

  };

  auto it = m_clientList.begin();
  for(;it != m_clientList.end();++it){
    auto item =(*it);
    dosend(item.second);
  }

}
